From 0de66a695f4adcf79c5f817f1ad3f6feed457edb Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 29 Sep 2006 10:30:18 +0100 Subject: [PATCH] [HVM][VMX] Fix data copying in transition to/from vmxassist. In vmx_assist, the copy for new/old context and vmx assist magic are all using physical address, while hvm_copy will use the virtual address. This may cause problem when guest jump directly from real mode to paging mode. Signed-off-by: Yunhong Jiang Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/hvm.c | 53 ++++++++++++++++++++----------- xen/arch/x86/hvm/vmx/vmx.c | 14 ++++---- xen/include/asm-x86/hvm/support.h | 1 + 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index f84d93d5f6..e8ccdad0a6 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -389,44 +389,59 @@ void hvm_hlt(unsigned long rflags) } /* - * Copy from/to guest virtual. + * __hvm_copy(): + * @buf = hypervisor buffer + * @addr = guest virtual or physical address to copy to/from + * @size = number of bytes to copy + * @dir = HVM_COPY_IN / HVM_COPY_OUT + * @phy = interpret addr as physical or virtual address? + * Returns TRUE on success. */ -int hvm_copy(void *buf, unsigned long vaddr, int size, int dir) +static int __hvm_copy( + void *buf, unsigned long addr, int size, int dir, int phy) { struct vcpu *v = current; - unsigned long gfn; unsigned long mfn; - char *addr; + char *p; int count; - while (size > 0) { - count = PAGE_SIZE - (vaddr & ~PAGE_MASK); - if (count > size) - count = size; - - gfn = shadow_gva_to_gfn(v, vaddr); - mfn = mfn_x(sh_vcpu_gfn_to_mfn(v, gfn)); + while ( size > 0 ) + { + count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), size); - if (mfn == INVALID_MFN) + mfn = phy ? + get_mfn_from_gpfn(addr >> PAGE_SHIFT) : + mfn_x(sh_vcpu_gfn_to_mfn(v, shadow_gva_to_gfn(v, addr))); + if ( mfn == INVALID_MFN ) return 0; - addr = (char *)map_domain_page(mfn) + (vaddr & ~PAGE_MASK); + p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK); - if (dir == HVM_COPY_IN) - memcpy(buf, addr, count); + if ( dir == HVM_COPY_IN ) + memcpy(buf, p, count); else - memcpy(addr, buf, count); + memcpy(p, buf, count); - unmap_domain_page(addr); + unmap_domain_page(p); - vaddr += count; - buf += count; + addr += count; + buf += count; size -= count; } return 1; } +int hvm_copy_phy(void *buf, unsigned long paddr, int size, int dir) +{ + return __hvm_copy(buf, paddr, size, dir, 1); +} + +int hvm_copy(void *buf, unsigned long vaddr, int size, int dir) +{ + return __hvm_copy(buf, vaddr, size, dir, 0); +} + /* * HVM specific printbuf. Mostly used for hvmloader chit-chat. */ diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 884acb3cea..b9b271a987 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1371,7 +1371,7 @@ static int vmx_assist(struct vcpu *v, int mode) u32 cp; /* make sure vmxassist exists (this is not an error) */ - if (!hvm_copy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), HVM_COPY_IN)) + if (!hvm_copy_phy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), HVM_COPY_IN)) return 0; if (magic != VMXASSIST_MAGIC) return 0; @@ -1385,20 +1385,20 @@ static int vmx_assist(struct vcpu *v, int mode) */ case VMX_ASSIST_INVOKE: /* save the old context */ - if (!hvm_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN)) + if (!hvm_copy_phy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN)) goto error; if (cp != 0) { if (!vmx_world_save(v, &c)) goto error; - if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_OUT)) + if (!hvm_copy_phy(&c, cp, sizeof(c), HVM_COPY_OUT)) goto error; } /* restore the new context, this should activate vmxassist */ - if (!hvm_copy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), HVM_COPY_IN)) + if (!hvm_copy_phy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), HVM_COPY_IN)) goto error; if (cp != 0) { - if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_IN)) + if (!hvm_copy_phy(&c, cp, sizeof(c), HVM_COPY_IN)) goto error; if (!vmx_world_restore(v, &c)) goto error; @@ -1412,10 +1412,10 @@ static int vmx_assist(struct vcpu *v, int mode) */ case VMX_ASSIST_RESTORE: /* save the old context */ - if (!hvm_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN)) + if (!hvm_copy_phy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN)) goto error; if (cp != 0) { - if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_IN)) + if (!hvm_copy_phy(&c, cp, sizeof(c), HVM_COPY_IN)) goto error; if (!vmx_world_restore(v, &c)) goto error; diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h index 4a0161298e..1052a922ca 100644 --- a/xen/include/asm-x86/hvm/support.h +++ b/xen/include/asm-x86/hvm/support.h @@ -138,6 +138,7 @@ extern int hvm_enabled; enum { HVM_COPY_IN = 0, HVM_COPY_OUT }; extern int hvm_copy(void *buf, unsigned long vaddr, int size, int dir); +extern int hvm_copy_phy(void *buf, unsigned long vaddr, int size, int dir); extern void hvm_setup_platform(struct domain* d); extern int hvm_mmio_intercept(ioreq_t *p); -- 2.30.2